package com.ayq.activiti.manager.service.impl;

import com.ayq.activiti.common.util.GlobalHttpSessionUtils;
import com.ayq.activiti.common.util.PageParams;
import com.ayq.activiti.common.util.Ret;
import com.ayq.activiti.manager.config.ActivitiIdGenerator;
import com.ayq.activiti.manager.service.CustomModelService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @Author tangsy
 * @Date 2021/3/25 10:05
 */
@Service
public class CustomModelServiceImpl implements CustomModelService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private ActivitiIdGenerator activitiIdGenerator;
    @Autowired
    private GlobalHttpSessionUtils globalHttpSessionUtils;

    /**
     *
     * <p>保存流程模型</p>
     * <p>方法名:saveModel</p>
     * @Author ayq
     * @Date 2021/3/25 10:08
     * @Param [modelId, name, description, json_xml, svg_xml, outStream]
     * @Return void
     */
    @Override
    public void saveModel(String modelId, String name, String description, String json_xml, String svg_xml, ByteArrayOutputStream outStream) throws Exception {
        Model model = repositoryService.getModel(modelId);
        ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
        modelJson.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelJson.put(ModelDataJsonConstants.MODEL_REVISION, modelJson.get(ModelDataJsonConstants.MODEL_REVISION).intValue() + 1);
        model.setMetaInfo(modelJson.toString());
        model.setName(name);
        model.setTenantId(globalHttpSessionUtils.getCurrentUserId());
      /*//获取模型,校验模型是否重复
      int count = Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(model.getName()).count()));
      if (count != 0 ) {
        LOGGER.error("模型KEy重复，请更改文件名");
        throw new ActivitiException("模型KEy重复，请更改文件名");
      }*/
        repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));
        InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
        TranscoderInput input = new TranscoderInput(svgStream);
        PNGTranscoder transcoder = new PNGTranscoder();
        outStream = new ByteArrayOutputStream();
        TranscoderOutput output = new TranscoderOutput(outStream);
        transcoder.transcode(input, output);
        final byte[] result = outStream.toByteArray();
        repositoryService.saveModel(model);
        repositoryService.addModelEditorSourceExtra(model.getId(), result);
    }

    /**
     *
     * <p>编辑时获取模型数据</p>
     * <p>方法名:getEditorJson</p>
     * @Author ayq
     * @Date 2021/3/25 10:20
     * @Param [modelId, modelNode]
     * @Return com.fasterxml.jackson.databind.node.ObjectNode
     */
    @Override
    public ObjectNode getEditorJson(String modelId,ObjectNode modelNode) throws Exception {
        Model model = repositoryService.getModel(modelId);
        if (model != null) {
            if (StringUtils.isNotEmpty(model.getMetaInfo())) {
                modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
            } else {
                modelNode = objectMapper.createObjectNode();
                modelNode.put(ModelDataJsonConstants.MODEL_NAME, model.getName());
            }
            modelNode.put(ModelDataJsonConstants.MODEL_ID, model.getId());
            ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
                    new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
            modelNode.put("model", editorJsonNode);
        }
        return modelNode;
    }

    /**
     * <p>获取对应系统流程菜单并汉化</p>
     * <p>方法名:getStencilset</p>
     * @Author ayq
     * @Date 2021/3/25 10:25
     * @Param [stencilsetStream]
     * @Return java.lang.String
     */
    @Override
    public String getStencilset(InputStream stencilsetStream) throws Exception {
        stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("static/stencilset/stencilset-zh-user1.json");
        return IOUtils.toString(stencilsetStream, "utf-8");
    }

    /**
     *
     * <p>模型列表</p>
     * <p>方法名:modelList</p>
     * @Author ayq
     * @Date 2021/3/25 10:30
     * @Param [pageParams]
     * @Return void
     */
    @Override
    public void modelList(PageParams pageParams) {
        List<Model> models = repositoryService.createModelQuery().orderByCreateTime().desc().listPage(pageParams.getPage(), pageParams.getLimit());
        pageParams.setRecords(models);
    }

    /**
     *
     * <p>创建空模型</p>
     * <p>方法名:newModel</p>
     * @Author ayq
     * @Date 2021/3/25 10:33
     * @Param [request, response]
     * @Return void
     */
    @Override
    public String newModel(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //初始化一个空模型
        Model model = repositoryService.newModel();
        //设置一些默认信息
        String name = "new-" + activitiIdGenerator.getNextId();
        String description = "";
        int revision = 1;
        String key = activitiIdGenerator.getNextId();
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());
        model.setTenantId(globalHttpSessionUtils.getCurrentUserId());
        repositoryService.saveModel(model);
        String id = model.getId();
        //完善ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace",
                "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.put("stencilset", stencilSetNode);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
        return id;
    }

    /**
     *
     * <p>打包方式部署流程模型</p>
     * <p>方法名:deployModle</p>
     * @Author ayq
     * @Date 2021/3/25 10:37
     * @Param [file, zipInputStream, bytes,bpmnBytes]
     * @Return Ret
     */
    @Override
    public Ret deployModle(MultipartFile file, ZipInputStream zipInputStream, byte[] bytes, byte[] bpmnBytes) throws Exception {
        // 获取原始名字
        String fileName = file.getOriginalFilename();
        // 获取文件后缀之前的名称
        String name = fileName.substring(0, fileName.lastIndexOf("."));
        // 获取文件后缀名
        String prefixName = fileName.substring(fileName.lastIndexOf("."));
        //获取图片信息
        zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));
        ZipEntry entry = zipInputStream.getNextEntry();
        while (entry != null) {
            if (!entry.isDirectory()) {
                String entryName = entry.getName();
                String substring = entryName.substring(fileName.lastIndexOf("."));
                if (entryName.contains(".png")) {
                    bytes = IoUtil.readInputStream(zipInputStream, entryName);
                }
                if (entryName.contains(".bpmn")) {
                    bpmnBytes = IoUtil.readInputStream(zipInputStream, entryName);
                }
            }
            entry = zipInputStream.getNextEntry();
        }
        //设置流程标识
        String nextId = activitiIdGenerator.getNextId();
       /* //获取流程构建器
        final DeploymentBuilder deployment = repositoryService.createDeployment();
        deployment.key(nextId).name(name);
        // 根据文件部署流程
        if (".zip".equals(prefixName)) {
            zipInputStream = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));
            deploy = deployment.addZipInputStream(zipInputStream).deploy();
        }*/
        //校验文件是否合法
        if (bpmnBytes == null || bytes == null) {
            return Ret.error("文件格式校验不匹配");
        }
        //获取流程资源
        InputStream in = new ByteArrayInputStream(bpmnBytes);
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        //读取xml文件
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(in);
        //将xml文件转换成BpmnModel
        BpmnModel bpmnModel = converter.convertToBpmnModel((XMLStreamReader) reader);
        //将BpmnModel转换成ObjectNode
        ObjectNode jsonNodes = new BpmnJsonConverter().convertToJson(bpmnModel);
        //初始化一个空模型
        Model model = repositoryService.newModel();
        //设置一些默认基础信息模型
        String description = "";
        int revision = 1;
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
        model.setName(name);
        model.setKey(nextId);
        model.setMetaInfo(modelNode.toString());
        model.setTenantId(globalHttpSessionUtils.getCurrentUserId());
        repositoryService.saveModel(model);
        //保存模型字节数据
        String id = model.getId();
        repositoryService.addModelEditorSourceExtra(id, bytes);
        repositoryService.addModelEditorSource(id, jsonNodes.toString().getBytes("utf-8"));
        return Ret.ok("上传成功", null);
    }

    /**
     *
     * <p>删除流程模型</p>
     * <p>方法名:deleteModel</p>
     * @Author ayq
     * @Date 2021/3/25 10:53
     * @Param [id]
     * @Return boolean
     */
    @Override
    public boolean deleteModel(String id) {
        Model model = repositoryService.createModelQuery().modelId(id).singleResult();
        long count = repositoryService.createDeploymentQuery().deploymentKey(model.getKey()).count();
        if (Integer.parseInt(String.valueOf(count)) == 0) {
            repositoryService.deleteModel(id);
            return true;
        } else {
            return false;
        }
    }
}
